/*
 * @Author: Author && Email
 * @Date: 2024-03-17 19:09:43
 * @LastEditors: Author && Email
 * @LastEditTime: 2024-03-17 20:29:53
 * @FilePath: \MDK-ARMd:\WorkSpace\PRJ\Washing_machine\software\Washing_machine_V1\User\moudle\ds18b20\ds18b20.c
 * @Description: 
 * 
 * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. 
 */
#include "ds18b20.h"

/****************************************************************************
函数名：delay_us
功能：微秒级延时
输入：延时数据
输出：无
返回值：无
备注：
****************************************************************************/
static void delay_us(uint32_t time)
{
  time *= 10;
	while(time)
		time--;
}

/**
 * @brief  DS18B20 复位
 * @param  无
 * @return 无
 * @note 将总线拉低 480us - 960us 启动复位，然后等待 15us 检测存在脉冲
 */
void Ds18b20_Reset(void)
{
	IO_DS18B20_SET();
	bsp_ds18b20_output();
	
	//拉低总线 750us
	IO_DS18B20_RESET();
	delay_us(800);
	
	//释放总线，等待存在脉冲
	IO_DS18B20_SET();
	delay_us(15);
}
/**
 * @brief  检测存在脉冲	
 * @param  无
 * @return   存在脉冲: 0 
 *         不存在脉冲: 1
 */
uint8_t Ds18B20_CheckPulse(void)
{
	/* 超时计数，若设备不存在，需要退出，不能一直等待 */
	uint8_t Time_Count = 0;
	
	//将 GPIO 改成输入模式下
	IO_DS18B20_SET();
	bsp_ds18b20_input();
	
	/* 对应时序中的 DS18B20 等待 (15 - 60)us */
	while (IO_DS18B20_READ() && Time_Count < 200)
	{
		Time_Count++;
		delay_us(1);
	}
	
	/* 已经过去了 100us 存在脉冲还没到来，代表设备不存在 */
	if (Time_Count >= 200)
		return 1;   
	/* 脉冲到来，复位超时计数 */
	else
		Time_Count = 0;
	
	IO_DS18B20_SET();
	/* 对应时序中的 DS18B20 存在脉冲 (60 - 240)us */
	while (IO_DS18B20_READ()==RESET && Time_Count < 240)
	{
		Time_Count++;
		delay_us(1);
	}
	/* 由时序图可知，存在脉冲最长不得超过 240us */
	if (Time_Count >= 240)
		return 2;
	else
		return 3;    //检测到存在脉冲
}
/**
 * @brief  读取1bit数据 
 * @param  无
 * @return 读取到1Bit的数据
 * @note   先将总线拉低 15us 后，读取总线状态
 */ 
uint8_t Ds18b20_Read_Bit(void)
{
	uint8_t dat;
	//输出模式
	IO_DS18B20_SET();
	bsp_ds18b20_output();
	
	//先拉低总线 15us 后读取总线状态
	IO_DS18B20_RESET();
	delay_us(15);
	
	//下面要读取总线值，将引脚设置成输入模式
	IO_DS18B20_SET();
	bsp_ds18b20_input();
	
	if (IO_DS18B20_READ() == SET)
		dat = 1;
	else
		dat = 0;
	
	//读取周期至少 60us
	delay_us(50);
	
	return dat;
}
/** 
 * @brief  从 DS18B20 上读取 1Byte
 * @param  无
 * @return 读到的8位数据
 * @note   低位到高位
 */
uint8_t Ds18B20_Read_Byte(void)
{
	uint8_t data = 0x00,mask;
	
	bsp_ds18b20_input();
	for (mask = 0x01;mask != 0;mask <<= 1)
	{
		if (Ds18b20_Read_Bit() == SET)
			data |= mask;
		else
			data &= ~mask;
	}
	
	return data;
}
/**
 * @brief  写入一字节数据，低位先行
 * @param  data 写入的数据 
 * @return 无
 * @note  写0: 由时序图可知，拉低总线至少 60us 表示写 0
          写1: 由时序图可知，拉低总线大于 1us 并且小于 15us 后，紧接着拉高总线，总时间超过 60us
          写周期必须有 1us 的恢复时间
 */
void Ds18B20_Write_Byte(uint8_t data)
{
	uint8_t mask;
	
	bsp_ds18b20_output();
	for (mask = 0x01;mask != 0;mask <<= 1)
	{
		IO_DS18B20_RESET();
		
		//写0
		if ((data & mask) == RESET)
		{
			/* 拉低总线至少 60us */
			IO_DS18B20_RESET();
			delay_us(70);
			
			//2us 的恢复时间
			IO_DS18B20_SET();
			delay_us(2);
		}
		else  //写1
		{
			/* 拉低总线大于 1us 并且小于 15us */
			IO_DS18B20_RESET();
			delay_us(9);
			
			/* 拉高总线，总时间超过 60us */
			IO_DS18B20_SET();
			delay_us(55);
		}
	}
}

/**
 * @brief  开始温度转换
 * @param  无
 * @return 从DS18B20上读取到的温度值
 * @note   此获取方法为跳过 ROM 读取,适合于总线上只有一个设备
 */
void ds18b20_start_convert(void)
{
	Ds18b20_Reset();	   
	Ds18B20_CheckPulse();	 
	Ds18B20_Write_Byte(0XCC);				/* 跳过 ROM */
	Ds18B20_Write_Byte(0X44);				/* 开始转换 */
}

/**
 * @brief  获取温度
 * @param  无
 * @return 从DS18B20上读取到的温度值
 * @note   此获取方法为跳过 ROM 读取,适合于总线上只有一个设备
 */
int16_t ds18b20_temp_get(void)
{
	uint8_t tpmsb, tplsb;
	short s_tem;
	uint16_t f_tem;
	
	Ds18b20_Reset();	   
	Ds18B20_CheckPulse();	 
	Ds18B20_Write_Byte(0XCC);				/* 跳过 ROM */
	Ds18B20_Write_Byte(0XBE);				/* 读温度值 */
	
	tplsb = Ds18B20_Read_Byte();		 
	tpmsb = Ds18B20_Read_Byte(); 
	
	s_tem = tpmsb<<8;
	s_tem = s_tem | tplsb;
	
	if( s_tem < 0 )		/* 负温度 */
	{
		f_tem = (~s_tem+1) * 625 /10000;	
		return (0-f_tem); 	
	}
	else
	{
		f_tem = s_tem * 625 / 10000;
		return f_tem; 	
	}
}

